package main

import (
	"fmt"
	"os"
)

func main() {
	/*
		3.文件打开与关闭
			（1）文件打开模式：
				const (
					O_RDONLY int = syscall.O_RDONLY // 只读模式打开文件
					O_WRONLY int = syscall.O_WRONLY // 只写模式打开文件
					O_RDWR   int = syscall.O_RDWR   // 读写模式打开文件
					O_APPEND int = syscall.O_APPEND // 写操作时将数据附加到文件尾部
					O_CREATE int = syscall.O_CREAT  // 如果不存在将创建一个新文件
					O_EXCL   int = syscall.O_EXCL   // 和O_CREATE配合使用，文件必须不存在
					O_SYNC   int = syscall.O_SYNC   // 打开文件用于同步I/O
					O_TRUNC  int = syscall.O_TRUNC  // 如果可能，打开时清空文件
				)

			（2）文件的打开与关闭操作：
				func Create(name string) (file *File, err error)
					//创建一个空文件，注意当文件已经存在时，会覆盖掉原文件，不会报错
				func Open(name string) (file *File, err error)
					//打开一个文件，注意打开的文件只能读，不能写和创建
				func OpenFile(name string, flag int, perm FileMode) (file *File, err error)
					//以指定的权限打开文件
				func (f *File) Close() error
					//关闭文件，关闭后不可读写

			其实 os.Create 等价于：OpenFile(name, O_RDWF|O_CREATE|O_TRUNK, 0666)

		4.File 文件读操作
			（1）func (f *File) Stat() (fi FileInfo, err error)
					获取文件的信息，里面有文件的名称、大小、修改时间等
			（2）func (f *File) Read(b []byte) (n int, err error)
					从文件中一次性读取 b 大小的数据，当读到文件结尾时，返回一个 EOF 错误
			（3）func (f *File) ReadAt(b []byte, off int64) (n int, err error)
					从文件中指定的位置（off）一次性读取 b 大小的数据
			（4）func ReadDir(name string) ([]DirEntry, error)
					读取目录并返回排好序的文件以及子目录名切片
			（5）func (f *File) Seek(offset int64, whence int) (ret int64, err error)
					seek 设置下一次 读/写 的位置。offset 为相对偏移量，
					而 whence 决定相对位置：0 为相对文件开头，1 为相对当前位置，2 为相对文件结尾。
					返回新的偏移量（相对开头）和可能的错误

		5.File 文件写操作
			（1）func (f *File) Write(b []byte) (n int, err error)
					Write 向文件中写入 len(b) 字节数据，
					返回写入的字节数和可能遇到的任何错误。
					如果返回值 n != len(b)，本方法会返回一个 非nil 的错误

			（2）func (f *File) WriteString(s string) (ret int, err error)
					WriteString 类似 Write，但接受一个字符串参数

			（3）func (f *File) WriteAt(b []byte, off int64) (n int, err error)
					WriteAt 在指定的位置（相对于文件开始位置）写入 len(b) 字节数据。
					返回写入的字节数和可能遇到的任何错误。
					如果返回值 n != len(b)，本方法会返回一个 非nil 的错误。
            （4）func WriteFile(name string, data []byte, perm FileMode) error
                    name：要写入的文件的路径。
                    data：要写入的数据，通常是一个字节切片（[]byte）。
                    perm：文件的权限模式，通常使用 os.ModePerm 或其他 os.FileMode 常量。
                    如果路径不存在，os.WriteFile 会创建一个新文件，如果文件已存在，会覆盖文件原有内容。

		6.进程相关操作（了解）
			（1）func Exit(code int)
					让当前程序以给出的状态码（code）退出。一般来说，状态码 0 表示成功，非0 表示出错。程序会立刻终止，defer 的函数不会被执行。
			（2）func Getuid() int
					获取调用者的 用户ID
			（3）func Geteuid() int
					获取调用者的 有效用户ID
			（4）func Getgid() int
					获取调用者的 组ID
			（5）func Getegid() int
					获取调用者的 有效组ID
			（6）func Getgroups() ([]int, error)
					获取调用者 所在的所有组的组ID
			（7）func Getpid() int
					获取调用者 所在进程的进程ID
			（8）func Getppid() int
					获取调用者 所在进程的父进程的进程ID
			（9）func Getwd() int
				Get Working Directory 获取当前 工作目录的路径

		7.环境相关操作（了解）
			（1）func Hostname() (name string, err error)
					获取主机名
			（2）func Getenv(key string) string
					获取某个环境变量
			（3）func Setenv(key, value string) error
					设置一个环境变量，失败返回错误，
					经测试当前设置的环境变量只在 当前进程有效
						（当前进程衍生的所有的 Go程序都可以拿到，子 goroutine 与 父goroutine的环境变量可以互相获取）
					进程退出消失
			（4）func Clearenv()
					删除当前程序已有的所有环境变量.不会影响当前电脑系统的环境变量，这些环境变量都是对当前 Go程序而言的

	*/
	//fmt.Println("------------------------文件打开与关闭-----------------------------")
	////只能读
	//f1, _ := os.Open("a.txt") //打开的文件必须存在
	//fmt.Println("f1.Name():", f1.Name())
	//
	////根据第二个打开模式参数 可以指定权限为读写或者创建
	//f2, _ := os.OpenFile("a1.txt", os.O_RDWR|os.O_CREATE, 0755)
	//fmt.Println("f2.Name():", f2.Name())
	//
	//err := f1.Close()
	//fmt.Println("err:", err)
	//err2 := f2.Close()
	//fmt.Println("err2:", err2)
	///*
	//	f1.Name(): a.txt
	//	f2.Name(): a1.txt
	//	err: <nil>
	//	err2: <nil>
	//*/
	//
	//fmt.Println("-----------------------Read--------------------------")
	//
	//fx, _ := os.Open("喜羊羊.txt")
	//fmt.Println(fx.Name())
	//for true {
	//	buf := make([]byte, 3) //设置一个缓冲区，一次读入 4 个字节
	//	n, err := fx.Read(buf) //将读取的内容放入缓冲区内
	//	fmt.Println(string(buf))
	//	fmt.Printf("n:%v\n", n)
	//	if err == io.EOF { //表示文件读取完毕
	//		break
	//	}
	//}
	//fx.Close()
	//
	//fmt.Println("------------------------ReadAt--------------------------")
	//buf := make([]byte, 15)
	//fh, _ := os.Open("灰太狼.txt")
	//n, _ := fh.ReadAt(buf, 3)
	//fmt.Println(n)
	//fmt.Println(string(buf))
	//fh.Close()
	//
	//fmt.Println("----------------------ReadDir--------------------------")
	//fo, err := os.Open("E:/代码文件/GO/src/go-basic/Go语言标准库/os")
	//if err != nil {
	//	fmt.Println("err:", err)
	//}
	//de, _ := fo.ReadDir(-1) //返回一个切片de
	//for _, v := range de {
	//	fmt.Println("v.IsDir():", v.IsDir())
	//	fmt.Println("v.Name():", v.Name())
	//}
	//
	//fmt.Println("------------------------seek--------------------------")
	//fh1, _ := os.Open("灰太狼.txt") //打开文件后，光标默认在文件开头
	//fh1.Seek(3, 0)               //从索引值为 3 处开始读
	//buf1 := make([]byte, 15)     //设置缓冲区
	//n1, _ := fh1.Read(buf1)
	//fmt.Println("n1:", n1)
	//fmt.Println("string(buf1):", string(buf1))
	//
	//fmt.Println("-----------------------Stat-------------------------")
	//fx1, _ := os.Open("喜羊羊.txt") //打开文件后，光标默认在文件开头
	//fInfo, _ := fx1.Stat()
	//fmt.Println("fx1是否是一个文件：", fInfo.IsDir())
	//fmt.Println("fx1文件的修改时间：", fInfo.ModTime().String())
	//fmt.Println("fx1文件的名称：", fInfo.Name())
	//fmt.Println("fx1文件的大小：", fInfo.Size())
	//fmt.Println("fx1文件的权限：", fInfo.Mode().String())
	///*
	//	fx1是否是一个文件： false
	//	fx1文件的修改时间： 2023-06-18 18:16:02.8416779 +0800 CST
	//	fx1文件的名称： 喜羊羊.txt
	//	fx1文件的大小： 22
	//	fx1文件的权限： -rw-rw-rw-
	//*/
	//
	////fmt.Println("-------------------------Write-------------------------")
	////fx2, _ := os.OpenFile("喜羊羊.txt", os.O_RDWR|os.O_APPEND, 0755) //以读写模式打开文件，并且在写操作时将数据附加到文件尾部
	////fx2.Write([]byte("灰太狼最酷了！"))
	////fx2.Close()

	fmt.Println("----------------------WriteString-----------------------")
	fh2, _ := os.OpenFile("灰太狼.txt", os.O_RDWR|os.O_TRUNC, 0775) //以读写模式打开文件，并且打开时清空文件
	//fh2.Write([]byte("hei我爱喜羊羊！\n喜羊羊最聪明啦！"))
	text := make([]byte, 10)
	n, err := fh2.Read(text)
	if err != nil {
		fmt.Println("err", err.Error())
	}
	fmt.Println(n)
	//
	//fmt.Println("----------------------WriteAt---------------------------")
	//fhh, _ := os.OpenFile("a.txt", os.O_RDWR, 0775) //以读写模式打开文件
	//fhh.WriteAt([]byte("hhh"), 3)                   //从索引值为3的地方开始写入 hhh 并覆盖原来当前位置的数据
	//fhh.Close()
	//
	//fmt.Println("-----------------------Getwd----------------------------")
	//wd, err := os.Getwd()
	//if err != nil {
	//	fmt.Println("Error:", err)
	//	return
	//}
	//fmt.Println("Current working directory:", wd)
	//
	//fmt.Println("------------------进程相关操作-------------------------")
	//
	//// 获得当前正在运行的进程id
	//fmt.Printf("os.Getpid(): %v\n", os.Getpid())
	//// 父id
	//fmt.Printf("os.Getppid(): %v\n", os.Getppid())
	//
	//// 设置新进程的属性
	//attr := &os.ProcAttr{
	//	// files指定新进程继承的活动文件对象
	//	// 前三个分别为，标准输入、标准输出、标准错误输出
	//	Files: []*os.File{os.Stdin, os.Stdout, os.Stderr},
	//	// 新进程的环境变量
	//	Env: os.Environ(),
	//}
	//
	//// 开始一个新进程
	//p, err := os.StartProcess("c:/windows/system32/notepad.exe", []string{"c:/windows/system32/notepad.exe", "d:/a.txt"}, attr)
	//if err != nil {
	//	fmt.Println(err)
	//}
	//fmt.Println(p)
	//fmt.Println("进程ID：", p.Pid)
	//
	//// 通过进程ID查找进程
	//p2, _ := os.FindProcess(p.Pid)
	//fmt.Println(p2)
	//
	//// 等待10秒，执行函数
	//time.AfterFunc(time.Second*10, func() {
	//	// 向p进程发出退出信号
	//	p.Signal(os.Kill)
	//})
	//
	//// 等待进程p的退出，返回进程状态
	//ps, _ := p.Wait()
	//fmt.Println(ps.String())
	//
	//fmt.Println("----------------------------环境相关操作-----------------------------")
	//// 获得所有环境变量
	//s := os.Environ()
	//fmt.Printf("s: %v\n", s)
	//// 获得某个环境变量
	//s2 := os.Getenv("GOPATH")
	//fmt.Printf("s2: %v\n", s2)
	//// 设置环境变量
	//os.Setenv("env1", "env1")
	//s2 = os.Getenv("aaa")
	//fmt.Printf("s2: %v\n", s2)
	//fmt.Println("--------------")
	//
	//// 查找
	//s3, b := os.LookupEnv("env")
	//fmt.Printf("b: %v\n", b)
	//fmt.Printf("s3: %v\n", s3)
	//
	//// 替换
	//os.Setenv("NAME", "gopher")
	//os.Setenv("BURROW", "/usr/gopher")
	//
	//os.ExpandEnv("$NAME lives in ${BURROW}.")
	//
	//// 清空环境变量
	//// os.Clearenv()

}
